www.gusucode.com > VANET Toolbox- A Vehicular Network Simulator based on DES 程序工具箱matlab源码 > VANET Toolbox- A Vehicular Network Simulator based on DES/VANET_Toolbox/VANET_Toolbox_multiChannel_2018b/des_MAC_OBU.m

    classdef des_MAC_OBU< matlab.DiscreteEventSystem & matlab.system.mixin.Propagates & matlab.system.mixin.SampleTime      
    properties   %Tunable properties
        Retry_MAX=3;  %Retransmision Times (3-8)
        
        % EDCA Parameters 
        
        AIFSN_AC0=9 % AIFSN_AC0
        AIFSN_AC1=6 % AIFSN_AC1
        AIFSN_AC2=3 % AIFSN_AC2
        AIFSN_AC3=2 % AIFSN_AC3
        
        aCWmin=15      
        aCWmax=1023
                
        slottime=13 % Timeslot period (unit:s)
        sifs=32;         
        txAddr=0; % Transmitter Address (txAddr)                
        infraAddress=0; % Infrastructure BSSID        
%         broadcast=0; % Broadcast Option: 0 - off; 1 - on;                
    end
%     properties(DiscreteState)
%         
%         txPayloadPriority  % buffer payload priority
%                 
%         frameTIDFieldBuffer  % Buffer TIDField
%         frameSNBuffer        % Buffer SN        
%         frameRetryBuffer
%                 
%         intContention  % 0 is free                
%                
%     end        
    properties(Access = private) 
        txPayloadPriority  % buffer payload priority
                
        frameTIDFieldBuffer  % Buffer TIDField
        frameSNBuffer        % Buffer SN        
        frameRetryBuffer
                
        intContention  % 0 is free      
        % Contention Window, CWmin,CWmax, for each priority queue
        CWmin_AC0
        CWmax_AC0
        CWmin_AC1
        CWmax_AC1
        CWmin_AC2
        CWmax_AC2
        CWmin_AC3
        CWmax_AC3
        
        % backoff unit: TimeSlot
        % Calculated from [0 CWmin]
        backoff_AC0 
        backoff_AC1
        backoff_AC2
        backoff_AC3
        
        
        % Arbitrary Inter-Frame Space: Calculated from AIFSN
        AIFS_AC0
        AIFS_AC1
        AIFS_AC2
        AIFS_AC3
              
        % Record the transmission/retransmission times of the frames in
        % each AC; If more than 3 transmissions, discard frames.
        txNum_AC0
        txNum_AC1
        txNum_AC2
        txNum_AC3
        
        
        numFrame_AC0   % frame counter for AC0 
        numFrame_AC1
        numFrame_AC2
        numFrame_AC3
       
        propTime=3; % Air prop time: (unit: us)                
        payloadCounter   %Count how many payload enters storage 1
        numRx % number of waveforms received 
        RxDataSN % Squence Number of received data
        RxACKSN  % Squence Number of received ACK
        
        TxACTag % AC tag of Tx data
%         RxACTag % AC tag of Rx data
        
        dataTxDelay                
        dataRxDelay
        
        ackTxRxDelay
        
        ackTimeout %2 propTime + 1 SIFS + ACK transTime, i.e.,  length of ACK/bitrate in Mbps          
        waitForACK  % Squence Number (SN) of packets waiting for an ACK
        srcAddress  % Source address buffer when receiving a single cast packet
        dstAddress
        
        txType
        
        timestampBuffer
               
        V2Xmode

        
        backoffPause
                
        payloadLength
        waveformLength
        
        rxPayloadBuffer        
        txPayloadBuffer    % buffer payload 
        frameBodyBuffer      % Buffer data body
        payloadPosBuffer
        
        SIFS
        EIFS
        slotTime
        rxCRCerr
        
        txPower
        
        txtEnable        
        PLCA=0;
        
        brakeMode='ConLaneChange';
        
    end

    methods(Access = protected)
        %% setup properties
        function setupImpl(obj)
            coder.extrinsic('evalin');
            coder.extrinsic('rng');
            rng('shuffle')
            obj.SIFS=obj.sifs/1000000;
            obj.slotTime=obj.slottime/1000000;
            
            % evalin create error in code generation, hard code temporarily            
            obj.payloadLength=800;
            obj.waveformLength=3935;
            
            obj.rxPayloadBuffer=zeros(1,800);
            obj.txPayloadBuffer=zeros(1,800);
            obj.txPayloadPriority=0;
            obj.payloadCounter=0;
            
            obj.frameBodyBuffer=zeros(1,800);
            obj.frameSNBuffer=0;            
            obj.numRx=0;
            
            %numFrame indicates how many frames stored in each AC, should
            %be replaced by iterateImpl() input parameter. 
            obj.numFrame_AC0=0;
            obj.numFrame_AC1=0;
            obj.numFrame_AC2=0;
            obj.numFrame_AC3=0;
            
            %Define Contention Window (min, max) for Backoff Process
            obj.CWmin_AC0=obj.aCWmin;
            obj.CWmax_AC0=obj.aCWmax;
            
            obj.CWmin_AC1=obj.aCWmin;
            obj.CWmax_AC1=obj.aCWmax;
            
            % 13us one slot time
            
            obj.CWmin_AC2=(obj.aCWmin+1)/2-1; % 0-7
            obj.CWmax_AC2=obj.aCWmin;       % 0-15
            
            obj.CWmin_AC3=(obj.aCWmin+1)/4-1; % 0-3
            obj.CWmax_AC3=(obj.aCWmin+1)/2-1; % 0-7
            
            %Backoff timer for each AC
            obj.backoff_AC0=0;
            obj.backoff_AC1=0;
            obj.backoff_AC2=0;
            obj.backoff_AC3=0;
            %Define AIFS for each AC
            obj.AIFS_AC0=obj.AIFSN_AC0*obj.slotTime+obj.SIFS; % 0.149ms
            obj.AIFS_AC1=obj.AIFSN_AC1*obj.slotTime+obj.SIFS; % 0.110ms
            obj.AIFS_AC2=obj.AIFSN_AC2*obj.slotTime+obj.SIFS; % 0.071ms
            obj.AIFS_AC3=obj.AIFSN_AC3*obj.slotTime+obj.SIFS; % 0.058ms
            
            
            obj.intContention=0; %Internal Contention
                        
            %txNum records transmission time of one frame in each AC queue
            obj.txNum_AC0=0;
            obj.txNum_AC1=0;
            obj.txNum_AC2=0;
            obj.txNum_AC3=0;
            
            
            obj.RxDataSN=0;        
            
            obj.dataTxDelay=0.01;  % dataTxDelay= length(data)/bitrate                        
            obj.dataRxDelay=0.01;
            
            obj.ackTxRxDelay=975/10000000;
            obj.ackTimeout=2*obj.propTime/1000000+obj.SIFS+obj.ackTxRxDelay+obj.slotTime; 
            
            obj.waitForACK=zeros(10);
            obj.txType=0;
            
            obj.timestampBuffer=0;       
            obj.backoffPause=0;
            obj.payloadPosBuffer=zeros(1,2);
            
%           In DCF, EIFS = aSIFSTime + DIFS + ACKTxTime
%           In EDCA, EIFS - DIFS + AIFS[AC] = SIFS+ACKTxTime+AIFS[AC];
            obj.EIFS=obj.SIFS+ obj.ackTxRxDelay; % 97.5+ 32 + AIFS
            obj.rxCRCerr=0;
            
            obj.txPower=0;
            obj.srcAddress=0;
            obj.dstAddress=0;
            obj.RxACKSN=0;
            
            obj.txtEnable=1;
            obj.txtEnable=evalin('base','txtEnable');                       
            
            obj.V2Xmode='V2V';
            obj.V2Xmode = evalin('base', 'V2Xmode');
            
            obj.brakeMode='ConLaneChange';
            obj.brakeMode=evalin('base','brakeMode');            
        end
        
        %% matlab.sytem.mixin.Propagates
        function num=getNumInputsImpl(~)
            num=2;
        end
        
        function num=getNumOutputsImpl(~)
            num=2;
        end

        function [sz,dt,cp]=getDiscreteStateSpecificationImpl(~,~)
            sz=[1,1];
            dt='double';
            cp=false;
        end
        
        %% matlab.DiscreteEventSystem - setup storage 
        function entityTypes=getEntityTypesImpl(obj)
            entityTypes=[obj.entityType('payload','Payload')...
                         obj.entityType('frame','Frame')...
                         obj.entityType('waveform','Waveform')];
        end
        
        function [inputTypes,outputTypes]=getEntityPortsImpl(~)
            inputTypes={'payload','waveform'};
            outputTypes={'payload','waveform'};
        end
        
        function [storageSpec,I,O]=getEntityStorageImpl(obj)
            payloadStorage=obj.queueFIFO('payload',inf);    % 1-Payload buffer, input1 from upper layer.
            frameStorage=obj.queueFIFO('frame',inf);        % 2-frame buffer
            AC0=obj.queueFIFO('frame',inf);                 % 3-AC0
            AC1=obj.queueFIFO('frame',inf);                 % 4-AC1
            AC2=obj.queueFIFO('frame',inf);                 % 5-AC2
            AC3=obj.queueFIFO('frame',inf);                 % 6-AC3
            HCF=obj.queueFIFO('frame',inf);                 % 7-HCF
            Txwaveform=obj.queueFIFO('waveform',inf);       % 8-Txwaveform, Output 2 to wireless channel
            Rxwaveform=obj.queueFIFO('waveform',inf);       % 9-Rxwaveform, Input 2 from wireless channel
            TxFrame=obj.queueFIFO('payload',inf);           % 10- Output 1 to upper layer
            storageSpec=[payloadStorage,frameStorage,AC0,AC1,AC2,AC3,HCF,Txwaveform,Rxwaveform,TxFrame];            
            I=[1 9];
            O=[10 8];            
        end
                                    
       %% Self-defined methods
        % Listen - if channel is idle. 
        % Listen period -- AIFS
        % tag - AC0Listen <-> AC3Listen;
        % obj.hcfListen(entity,'AC0Listen',obj.AIFS_AC0);
        function events=hcfListen(obj,entity,tag)            
            coder.extrinsic('phy_ChannelSensing');
            coder.extrinsic('num2str');
            events=obj.initEventArray;
            hcfCS=0;
            hcfCS=phy_ChannelSensing(1,0,0); % Channel sensing
            tag=tag(tag~=0);
            if hcfCS==0  %Channel idle                
                switch tag
                    case 'AC0Listen'
                        
                        if obj.rxCRCerr==0 % Receive no Error packet, defer AIFS
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')' ' sense idle channel, defer access AIFS_AC0 ' num2str(obj.AIFS_AC0*1000) 'ms']);%defer access to AIFS
                            end
                            events=obj.eventTimer('AC0AIFS',obj.AIFS_AC0);
                        elseif obj.rxCRCerr==1 % Receive Error packet, defer EIFS instead of AIFS
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')' ' sense idle channel, defer access EIFS+AIFS_AC0 ' num2str((obj.EIFS+obj.AIFS_AC0)*1000) 'ms']);%defer access to AIFS                           
                            end
                            events=obj.eventTimer('AC0AIFS',obj.EIFS+obj.AIFS_AC0);
                        end
                        
                    case 'AC1Listen'                        
                        
                        if obj.rxCRCerr==0
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')'  ' sense idle channel, defer access AIFS_AC1 ' num2str(obj.AIFS_AC1*1000) 'ms']);%defer access to AIFS
                            end
                            events=obj.eventTimer('AC1AIFS',obj.AIFS_AC1);
                        elseif obj.rxCRCerr==1
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')'  ' sense idle channel, defer access EIFS+AIFS_AC1 ' num2str((obj.EIFS+obj.AIFS_AC1)*1000) 'ms']);%defer access to AIFS                            
                            end
                            events=obj.eventTimer('AC1AIFS',obj.EIFS+obj.AIFS_AC1);
                        end
                        
                    case 'AC2Listen'                                                
                        if obj.rxCRCerr==0
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')'  ' sense idle channel, defer access AIFS_AC2 ' num2str(obj.AIFS_AC2*1000) 'ms']);%defer access to AIFS
                            end
                            events=obj.eventTimer('AC2AIFS',obj.AIFS_AC2);
                        elseif obj.rxCRCerr==1
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')'  ' sense idle channel, defer access EIFS+AIFS_AC2 ' num2str((obj.EIFS+obj.AIFS_AC2)*1000) 'ms']);%defer access to AIFS
                            end
                            events=obj.eventTimer('AC2AIFS',obj.EIFS+obj.AIFS_AC2);
                        end
                        
                    case 'AC3Listen'                        
                        
                        if obj.rxCRCerr==0
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')'  ' sense idle channel, defer access AIFS_AC3 ' num2str(obj.AIFS_AC3*1000) 'ms']);%defer access to AIFS
                            end
                            events=obj.eventTimer('AC3AIFS',obj.AIFS_AC3);
                        elseif obj.rxCRCerr==1
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')'  ' sense idle channel, defer access obj.EIFS+AIFS_AC3 ' num2str((obj.EIFS+obj.AIFS_AC3)*1000) 'ms']);%defer access to AIFS                            
                            end
                            events=obj.eventTimer('AC3AIFS',obj.EIFS+obj.AIFS_AC3);
                        end
                        
                end                
            else
                if obj.txtEnable==1
                    disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame' num2str(entity.data.SN) '(AC' num2str(entity.data.ACTag) ...
                                ')'  ' sense busy channel, listen to another slottime ' num2str(obj.slotTime*1000) 'ms']);%defer access to AIFS
                end
                        events=obj.eventTimer(tag,obj.slotTime);% Listen                
            end  
        end
        


        % backoff;
        % Duty: 1. calculate contention window; 2. Set the AIFS timers to
        % call 'hcfBfCon' for AIFS by AIFS count down.
        function events=hcfBfStart(obj,entity,tag)                       
            coder.extrinsic('num2str');
            coder.extrinsic('randi');
%             rng(obj.txAddr);
%             
            tag=tag(tag~=0);
                    switch tag
                        case 'AC0backoff'                            
                            obj.backoff_AC0=randi([0 obj.CWmin_AC0]);
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  Frame ' num2str(entity.data.SN) ' (AC0) listen idle channel, backoff ' num2str(obj.backoff_AC0) ' timeslots;']);
                            end
                            if obj.backoff_AC0==0
                                if entity.data.Retry==0
                                    events=obj.intContentionCheck(entity);
                                else                      
                                    [~,events]=obj.extContentionCheck(entity);  
                                end 
                            else
                                if obj.txtEnable==1
                                    disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC0 Backoff left:' num2str(obj.backoff_AC0) '----------']);                    
                                end
                                obj.backoff_AC0=obj.backoff_AC0-1;
                                events=obj.eventTimer(tag,obj.slotTime); 
                            end                                                                                    
                        case 'AC1backoff'
                            obj.backoff_AC1=randi([ 0 obj.CWmin_AC1]);
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  Frame ' num2str(entity.data.SN) '(AC1) listen idle channel,backoff ' num2str(obj.backoff_AC1) ' timeslots;']);
                            end
                            if obj.backoff_AC1==0
                                if entity.data.Retry==0
                                    events=obj.intContentionCheck(entity);
                                else                      
                                    [~,events]=obj.extContentionCheck(entity);  
                                end 
                            else
                                if obj.txtEnable==1
                                    disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC1 Backoff left:' num2str(obj.backoff_AC1) '----------']);                    
                                end
                                obj.backoff_AC1=obj.backoff_AC1-1;
                                events=obj.eventTimer(tag,obj.slotTime); 
                            end
                            
                            
                        case 'AC2backoff'
                            
%                             
%                             temprandi  = randi([0 7]);
%                              disp(['randtemp= ' num2str(temprandi)]);
                            obj.backoff_AC2=randi([0 obj.CWmin_AC2]);
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  Frame ' num2str(entity.data.SN) '(AC2) listen idle channel,backoff ' num2str(obj.backoff_AC2) ' timeslots;']);
                            end
                            if obj.backoff_AC2==0
                                if entity.data.Retry==0
                                    events=obj.intContentionCheck(entity);
                                else                      
                                    [~,events]=obj.extContentionCheck(entity);  
                                end 
                            else
                                if obj.txtEnable==1
                                    disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC2 Backoff left:' num2str(obj.backoff_AC2) '----------']);
                                end
                                obj.backoff_AC2=obj.backoff_AC2-1;
                                events=obj.eventTimer(tag,obj.slotTime); 
                            end
                            
                            
                        case 'AC3backoff'
                            obj.backoff_AC3=randi([0 obj.CWmin_AC3]);
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  Frame ' num2str(entity.data.SN) '(AC3) listen idle channel,backoff ' num2str(obj.backoff_AC3) ' timeslots;']);
                            end
                            if obj.backoff_AC3==0
                                if entity.data.Retry==0
                                    events=obj.intContentionCheck(entity);
                                else                      
                                    [~,events]=obj.extContentionCheck(entity);  
                                end 
                            else
                                if obj.txtEnable==1
                                    disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC3 Backoff left:' num2str(obj.backoff_AC3) '----------']);                    
                                end
                                obj.backoff_AC3=obj.backoff_AC3-1;
                                events=obj.eventTimer(tag,obj.slotTime); 
                            end                                                        
                    end
                                   
        end
        
        % BackoffContinue called during backoff process AIFS by AIFS;
        % If backoff decrease to Zero, call internal Contention check;
        function events=hcfBfCont(obj,tag,entity)
            events=obj.initEventArray;
            tag=tag(tag~=0);
            switch tag
                case 'AC0backoff' 
                    if obj.backoff_AC0==0
                        if entity.data.Retry==0
                            events=obj.intContentionCheck(entity);
                        else                      
                            [~,events]=obj.extContentionCheck(entity);  
                        end 
                    else
                        obj.backoff_AC0=obj.backoff_AC0-1;
                        events=obj.eventTimer(tag,obj.slotTime);
                    end
                case 'AC1backoff'     
                    if obj.backoff_AC1==0
                        if entity.data.Retry==0
                            events=obj.intContentionCheck(entity);
                        else                      
                            [~,events]=obj.extContentionCheck(entity);  
                        end 
                    else
                        obj.backoff_AC1=obj.backoff_AC1-1;
                        events=obj.eventTimer(tag,obj.slotTime);
                    end
                case 'AC2backoff'   
                    if obj.backoff_AC2==0
                        if entity.data.Retry==0
                            events=obj.intContentionCheck(entity);
                        else                      
                            [~,events]=obj.extContentionCheck(entity);  
                        end 
                    else
                        obj.backoff_AC2=obj.backoff_AC2-1;
                        events=obj.eventTimer(tag,obj.slotTime);
                    end
                case 'AC3backoff'    
                    if obj.backoff_AC3==0
                        if entity.data.Retry==0
                            events=obj.intContentionCheck(entity);
                        else                      
                            [~,events]=obj.extContentionCheck(entity);  
                        end 
                    else
                        obj.backoff_AC3=obj.backoff_AC3-1;
                        events=obj.eventTimer(tag,obj.slotTime);
                    end
            end        
        end

        % Internal Contention Check
        % If internal contention exist, rebackoff
        % if no internal contention, forward 'Frame Entity' to 'HCF
        % Storage';
        function events=intContentionCheck(obj,entity)
            coder.extrinsic('num2str');
            if obj.intContention==0
%                 disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  Internal Contention Not Detected! Send to Tx Buffer......'])
                events=obj.eventForward('storage',7,0); %Forward to Tx buffer, storage 7 
                obj.intContention=1;
                switch entity.data.ACTag
                    case 0
                        obj.numFrame_AC0=obj.numFrame_AC0-1;
                    case 1
                        obj.numFrame_AC1=obj.numFrame_AC1-1;
                    case 2
                        obj.numFrame_AC2=obj.numFrame_AC2-1;
                    case 3
                        obj.numFrame_AC3=obj.numFrame_AC3-1;
                end                
            else
                if obj.txtEnable==1
                    disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':   Internal Contention Detected! Redo backoff .....@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.']);
                end
                events=obj.hcfReTx(entity);
            end
        end
        
        % External Check 
        % Task 1: Channel sensing, check if incoming transmission exist;
        % Task 2: Check is current node is transmitting;
        % Task 3: Buff the Sequence Number of packets awaiting sending.
        % Generate 'Waveform entity' in STORAGE 8; Create 'dataTx' timer
        % for simulating transmission delay.
        % If channel is busy or the current node is transmitting, redo backoff 
        function [entity,events]=extContentionCheck(obj,entity)
%             disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  retry times (extCon)' num2str(entity.data.Retry)]);                           
%             disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  External Contention NOT Detected! Send to Tx output......']);
%             disp(['dataTxDelay ' num2str(obj.dataTxDelay)]);                                    
                coder.extrinsic('num2str');
                coder.extrinsic('fcn_carGlobalDB');
                events=obj.initEventArray;
                
                obj.frameBodyBuffer=entity.data.Body;
                obj.TxACTag=entity.data.ACTag;
                obj.frameRetryBuffer=entity.data.Retry;
                
                if entity.data.Retry==0  % New frame                    
                   % Select receiver; 0 is broadcast; Then set to
                   % destination address: dstAddress
                                      
                    obj.dstAddress=entity.data.dstAddress;
                    
                    obj.frameSNBuffer=entity.data.SN;   
                    obj.timestampBuffer=entity.data.Timestamp;
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node'  num2str(obj.txAddr) ',  select destination: node ' num2str(obj.dstAddress)]); 
                    end
                    
                    
%                     if obj.infraAddress==0
                    if strcmp(obj.V2Xmode,'V2V')
                        entity.data.ToDS=0;
                        entity.data.FromDS=0;
                        entity.data.Address1=obj.dstAddress;
                        entity.data.Address2=obj.txAddr;
%                     elseif obj.infraAddress==88
                    elseif strcmp(obj.V2Xmode,'V2I')
                        entity.data.ToDS=1;
                        entity.data.FromDS=0;
                        entity.data.Address1=obj.infraAddress;
                        entity.data.Address2=obj.txAddr;
                        entity.data.Address3=obj.dstAddress;                        
                    else
                         if obj.txtEnable==1
                            disp('Error: wrong V2x mode selected.');
                         end
                     end

                    if obj.dstAddress~=0 && obj.dstAddress<1000000% Unicast              
                        % not support code generation
                        if ~ismember(obj.frameSNBuffer,obj.waitForACK)
                            pointer=length(obj.waitForACK(obj.waitForACK~=0))+1;
                            obj.waitForACK(pointer)=obj.frameSNBuffer;
%                             obj.waitForACK=[obj.waitForACK obj.frameSNBuffer];
                        end                            
                        switch entity.data.ACTag
                            case 0
                                events=obj.eventGenerate(8,'sendFrame_AC0',0,1);
                            case 1
                                events=obj.eventGenerate(8,'sendFrame_AC1',0,1);
                            case 2
                                events=obj.eventGenerate(8,'sendFrame_AC2',0,1);
                            case 3
                                events=obj.eventGenerate(8,'sendFrame_AC3',0,1);
                        end           
                        events=[events obj.eventTimer('dataTx',obj.dataTxDelay)];
                    else  % Broadcast 
                        switch entity.data.ACTag
                            case 0
                                events=obj.eventGenerate(8,'sendFrame_AC0',0,1);
                            case 1
                                events=obj.eventGenerate(8,'sendFrame_AC1',0,1);
                            case 2
                                events=obj.eventGenerate(8,'sendFrame_AC2',0,1);
                            case 3
                                events=obj.eventGenerate(8,'sendFrame_AC3',0,1);
                        end                    
                        events=[events obj.eventTimer('broadcast',obj.dataTxDelay)];
                    end     
                    
                    fcn_carGlobalDB('sent',entity.data.ACTag);
                    
                    
                else  % Retransmitted frame
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node'  num2str(obj.txAddr) ': This is a retransmitted frame']);
                    end
%                     disp(['(extCont-Retrans) entity.data.Address1 ' num2str(entity.data.Address1) 'entity.data.Address2 ' num2str(entity.data.Address2) 'entity.data.Address3 ' num2str(entity.data.Address3)]);
                    obj.frameSNBuffer=entity.data.SN;   
                    
                    if entity.data.ToDS==0 && entity.data.FromDS==0
                        obj.dstAddress=entity.data.Address1;                        
                    elseif entity.data.ToDS==1 && entity.data.FromDS==0
                        obj.dstAddress=entity.data.Address3;
                    else
                        if obj.txtEnable==1
                            disp('wrong ToDS/FromDS setting');
                        end
                    end                    
        
                      % not support code generation
                    if ~ismember(obj.frameSNBuffer,obj.waitForACK)
                        pointer=length(obj.waitForACK(obj.waitForACK~=0))+1;
                        obj.waitForACK(pointer)=obj.frameSNBuffer;
%                         obj.waitForACK=[obj.waitForACK obj.frameSNBuffer];
                    end                                        

                    switch entity.data.ACTag
                        case 0
                            events=obj.eventGenerate(8,'sendFrame_AC0',0,1);
                        case 1
                            events=obj.eventGenerate(8,'sendFrame_AC1',0,1);
                        case 2
                            events=obj.eventGenerate(8,'sendFrame_AC2',0,1);
                        case 3
                            events=obj.eventGenerate(8,'sendFrame_AC3',0,1);
                    end           
                    events=[events obj.eventTimer('dataTx',obj.dataTxDelay)];
                end
        end
        
        % Rebackoff happens when: 1. media is busy after last backoff (internal contention or external contention); 2. ACK not
        % received.
        % Duty: Double CWmin. Restart from 'Listen' stage.
        function events=hcfReBf(obj,entity)
            coder.extrinsic('num2str');
%             disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  retry times (hcfReBf)' num2str(entity.data.Retry)]);                
            events=obj.initEventArray;
            switch entity.data.ACTag
                case 0
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  rebackoff frame ' num2str(entity.data.SN)] );
                    end
                    if obj.CWmin_AC0*2<obj.CWmax_AC0
                        obj.CWmin_AC0=obj.CWmin_AC0*2;
                    else
                        obj.CWmin_AC0=obj.CWmax_AC0;
                    end
                    events=obj.hcfListen(entity, 'AC0Listen');
                case 1
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  rebackoff frame ' num2str(entity.data.SN)] );
                    end
                    if obj.CWmin_AC1*2<obj.CWmax_AC1
                        obj.CWmin_AC1=obj.CWmin_AC1*2;
                    else
                        obj.CWmin_AC1=obj.CWmax_AC1;
                    end
                    events=obj.hcfListen(entity, 'AC1Listen');
                case 2
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  rebackoff frame ' num2str(entity.data.SN)] );
                    end
                    if obj.CWmin_AC2*2<obj.CWmax_AC2
                        obj.CWmin_AC2=obj.CWmin_AC2*2;
                    else
                        obj.CWmin_AC2=obj.CWmax_AC2;
                    end
                    events=obj.hcfListen(entity, 'AC2Listen');
                case 3
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  rebackoff frame ' num2str(entity.data.SN)] );
                    end
                    if obj.CWmin_AC3*2<obj.CWmax_AC3
                        obj.CWmin_AC3=obj.CWmin_AC3*2;
                    else
                        obj.CWmin_AC3=obj.CWmax_AC3;
                    end
                    events=obj.hcfListen(entity, 'AC3Listen');
            end
            
        end
        
        % ReTransmission happens when ACK is timeout or corrupted.
        % obj.txNum record the number of transmission;
        % Check if retransmission times reach Retry_MAX: Yes - drop, send
        % next if there is any;  No - rebackoff, retransmit;
        function events=hcfReTx(obj,entity)
            coder.extrinsic('num2str');
            events=obj.initEventArray;
            switch entity.data.ACTag
                case 0
                    if obj.txNum_AC0==obj.Retry_MAX      %Retrans time more than 3, drop
                        obj.txNum_AC0=0;                    % Reset transmision times
                        obj.CWmin_AC0=obj.aCWmin;           % Reset CWmin
                        if obj.txtEnable==1
                            disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  retransmit 3 times, dropped, send next.']);                            
                        end                                                                       
                        
                         if ismember(entity.data.SN,obj.waitForACK) % Make sure the ACK is to the right data                                                                                               
                            for i=1:length(obj.waitForACK)                                           
                                if obj.waitForACK(i)==entity.data.SN                                
                                    obj.waitForACK(i)=0;                                    
                                    tempArray=obj.waitForACK(obj.waitForACK~=0);                                    
                                    tempIndex=length(tempArray);                                    
                                    obj.waitForACK(1:tempIndex)=tempArray;                                    
                                end                                
                            end
                         end
                        
                        if obj.numFrame_AC0>1               % If more packets are waiting, prepare to send next;
                            events=obj.eventIterate(3,'nextAC0',1);
                        else                                % If no packets in the AC queue, stay sleep;
%                             events=obj.hcfSleep();
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  has no more frames in AC' num2str(entity.data.ACTag) ' stored']);
                            end
                        end
                        events=[events obj.eventDestroy()];
                    else 
                        obj.txNum_AC0=obj.txNum_AC0+1;      % Transmission times increases by 1
%                         entity.data.Retry=1;
                        events=obj.hcfReBf(entity);         % Redo backoff 
                    end
                case 1
                    if obj.txNum_AC1==obj.Retry_MAX      %Retrans time more than 3, drop
                        obj.txNum_AC1=0;
                        obj.CWmin_AC1=obj.aCWmin;                        
                        if obj.txtEnable==1
                            disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': retransmit 3 times, dropped, send next.']);
                        end
                        
                        if obj.txtEnable==1
                            %%disp(['^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^SN ' num2str(entity.data.SN) ' waitforACK: ' num2str(obj.waitForACK) '^^^^^^^^^^^^^^^^^^^^^^']);
                        end
                        if ismember(entity.data.SN,obj.waitForACK) % Make sure the ACK is to the right data                                                                                               
%                             obj.waitForACK=obj.waitForACK(obj.waitForACK~=entity.data.SN);
                            for i=1:length(obj.waitForACK)                                           
                                if obj.waitForACK(i)==entity.data.SN                                
                                    obj.waitForACK(i)=0;                                    
                                    tempArray=obj.waitForACK(obj.waitForACK~=0);                                    
                                    tempIndex=length(tempArray);                                    
                                    obj.waitForACK(1:tempIndex)=tempArray;                                    
                                end                                
                            end
                         end
                        if obj.numFrame_AC1>1
                            events=obj.eventIterate(4,'nextAC1',1);
                        else
%                             events=obj.hcfSleep();
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': has no more frames in AC' num2str(entity.data.ACTag) ' stored']);
                            end
                        end
                        events=[events obj.eventDestroy()];
                    else 
                        obj.txNum_AC1=obj.txNum_AC1+1;
%                         entity.data.Retry=1;
                        events=obj.hcfReBf(entity);
                    end
                case 2
                    if obj.txNum_AC2==obj.Retry_MAX      %Retrans time more than 3, drop
                        obj.txNum_AC2=0;
                        obj.CWmin_AC2=obj.aCWmin;                        
                        if obj.txtEnable==1
                            disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': retransmit 3 times, dropped, send next.']);
                            %%disp(['^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^SN ' num2str(entity.data.SN) ' waitforACK: ' num2str(obj.waitForACK) '^^^^^^^^^^^^^^^^^^^^^^']);
                        end
                        
                        if ismember(entity.data.SN,obj.waitForACK) % Make sure the ACK is to the right data                                                                                               
%                             obj.waitForACK=obj.waitForACK(obj.waitForACK~=entity.data.SN);
                            for i=1:length(obj.waitForACK)
                                if obj.waitForACK(i)==entity.data.SN    
                                    obj.waitForACK(i)=0;        
                                    tempArray=obj.waitForACK(obj.waitForACK~=0);        
                                    tempIndex=length(tempArray);        
                                    obj.waitForACK(1:tempIndex)=tempArray;        
                                end    
                            end
                        end
                        if obj.numFrame_AC2>1
                            events=obj.eventIterate(5,'nextAC2',1);
                        else
%                             events=obj.hcfSleep();                            
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ': node' num2str(obj.txAddr) ' has no more frames in AC' num2str(entity.data.ACTag) ' stored']);
                            end
                        end
                        events=[events obj.eventDestroy()];
                    else 
                        obj.txNum_AC2=obj.txNum_AC2+1;
%                         entity.data.Retry=1;
                        events=obj.hcfReBf(entity);
                    end
                case 3

                    if obj.txNum_AC3==obj.Retry_MAX     %Retrans time more than 3, drop
                        obj.txNum_AC3=0;
                        obj.CWmin_AC3=obj.aCWmin;                        
                        if obj.txtEnable==1
                            disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': retransmit 3 times, dropped, send next.']);
%                             %%disp(['^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^SN ' num2str(entity.data.SN) ' waitforACK: ' num2str(obj.waitForACK) '^^^^^^^^^^^^^^^^^^^^^^']);
                        end
                        
                        
                        if ismember(entity.data.SN,obj.waitForACK) % Make sure the ACK is to the right data                                                                                               
%                             obj.waitForACK=obj.waitForACK(obj.waitForACK~=entity.data.SN);
                            for i=1:length(obj.waitForACK)
                                if obj.waitForACK(i)==entity.data.SN    
                                    obj.waitForACK(i)=0;        
                                    tempArray=obj.waitForACK(obj.waitForACK~=0);        
                                    tempIndex=length(tempArray);        
                                    obj.waitForACK(1:tempIndex)=tempArray;        
                                end    
                            end
                        end
%                         disp(['Updated WaitforACK ' num2str(obj.waitForACK)]); 
                        if obj.numFrame_AC3>1
                            events=obj.eventIterate(6,'nextAC3',1);
                        else
%                             events=obj.hcfSleep();
                            if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  has no more frames in AC' num2str(entity.data.ACTag) ' stored']);
                            end
                        end
                        
                        % -----------Performance lane changing special                                       
                        if strcmp(obj.brakeMode,'PerLaneChange') && entity.data.Address2==obj.PLCA                                                
                            events=[events obj.eventGenerate(10,'mgmGenUnACKed',0,10)];
                        end
                        %-----------------------------------------------------------------
                        
                        events=[events obj.eventDestroy()];
                    else                          
                        obj.txNum_AC3=obj.txNum_AC3+1;
%                         entity.data.Retry=1;
                        events=obj.hcfReBf(entity);
                    end
            end
                
        end        
        
    end
    
    methods
        function events=setupEvents(obj)            
            coder.extrinsic('phy_ChannelSensing');
            coder.extrinsic('evalin');
            coder.extrinsic('num2str');
            
            events=obj.initEventArray;
            phy_ChannelSensing(0,0,0);
            phy_ChannelSensing(2,0,0);
            
            if strcmp(obj.V2Xmode,'V2V')
                disp(['Node ' num2str(obj.txAddr) ' V2V mode selected!']);       
            elseif strcmp(obj.V2Xmode,'V2I')
                disp(['Node ' num2str(obj.txAddr) ' V2I mode selected! RSU address is ' num2str(obj.infraAddress)]);       
            else
                disp('Warning: V2x mode error! (0 or 1)')
            end       
                                           
        end
        
       %% matlab.DiscreteEventSystem - action methods
         
        % Action when 'Payload entity' enters STORAGE 1 of MAC layer;
        % Gather all info preparing for generating 'Frame entity';
        % 1. payloadCounter --> Frame Sequence Number (entity.data.SN);
        % 2. payload buffer --> Frame body (entity.data.Body);
        % 3. priority buffer--> Frame priority       
        function [entity,events] = payloadEntry(obj,~,entity,~)
            coder.extrinsic('num2str');
%             coder.extrinsic('str2num');
            coder.extrinsic('str2double');
            coder.extrinsic('evalin');
            coder.extrinsic('phy_psdu2waveform_data_mex');
            
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('mac');
            
            obj.payloadCounter=obj.payloadCounter+1; % In frameGenerateImpl(), entity.data.SN=obj.payloadCounter;            
            obj.txPayloadBuffer=entity.data.wsmp;
            obj.txPayloadPriority=entity.data.priority;                                           
            obj.payloadPosBuffer=entity.data.pos;
            obj.dstAddress=entity.data.dstAddress; 
                                  
            if strcmp(obj.brakeMode,'PerLaneChange')
                if entity.data.dstAddress>1000000
                    tempAdd='1000000';
                    tempAdd=num2str(entity.data.dstAddress);  
                    
                    frontAddress=0;
                    backAddress=0;                    
%                     frontAddress=str2num(tempAdd(2:4));
%                     backAddress=str2num(tempAdd(5:7));
                    
                    frontAddress=str2double(tempAdd(2:4));
                    backAddress=str2double(tempAdd(5:7));
                    
                    if frontAddress~=0
                        obj.dstAddress=frontAddress;
                    else
                        obj.dstAddress=backAddress;                     
                    end
                    
                end
                obj.PLCA=obj.dstAddress; % Performance Lane Changing Address (PLCA) unique;
            end
            
                        
%             [waveform,~]=phy_psdu2waveform(0,0,0,obj.txPayloadBuffer);  
            [waveform,~]=phy_psdu2waveform_data_mex(0,0,obj.txPayloadBuffer);  
            obj.dataTxDelay=length(waveform)/10000000;
            
            events=[obj.eventGenerate(2,'frame',0,1) obj.eventDestroy()];     %Switch from payload type to frame type              
            if obj.txtEnable==1
                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame' num2str(obj.payloadCounter) ' generated.']);
            end
        end
        
        % Generate 'Frame entity' in STORAGE 2.
        % Frame entity.data contains: 1. Payload 2.SN 3. ACTag.
        % Frame eneitty.sys contains: entity priority.
        % FORWARD each Frame entity to each AC queues.
        function [entity,events]=frameGenerate(obj,~,entity,~)    
            coder.extrinsic('num2str');    
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('mac');
            
            entity.data.Body=obj.txPayloadBuffer;            
            entity.data.SN=obj.payloadCounter;            
            entity.data.Retry=0;                                
            entity.data.Timestamp=obj.getCurrentTime();
            entity.data.dstAddress=obj.dstAddress;
                    
            switch obj.txPayloadPriority            
                case {1,2}  %AC0%                                 
                    entity.data.ACTag=0;                                              
                    entity.sys.priority=40;                    
                    events=obj.eventForward('storage',3,0);                    
                    if obj.txtEnable==1                    
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame' num2str(entity.data.SN) ' forwarded to AC0']);                        
                    end
                    
                case {0,3}  %AC1                
                    entity.data.ACTag=1;                    
                    entity.sys.priority=30;                    
                    events=obj.eventForward('storage',4,0);                    
                    if obj.txtEnable==1                                                   
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame' num2str(entity.data.SN) ' forwarded to AC1']);                        
                    end
                    
                case {4,5}  %AC2                
                    entity.data.ACTag=2;
                    entity.sys.priority=20;
                    events=obj.eventForward('storage',5,0);                    
                    if obj.txtEnable==1                    
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame' num2str(entity.data.SN) ' forwarded AC2']);                        
                    end
                    
                case {6,7}  %AC3               
                    entity.data.ACTag=3;                    
                    entity.sys.priority=10;                    
                    events=obj.eventForward('storage',6,0);                    
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame' num2str(entity.data.SN) ' forwarded to AC3']);
                    end
                    
                otherwise                    
                    events=obj.initEventArray;
                    
            end            
        end
        
        
        
        % Triger Conditions: 1. Frame entity generated in STORAGE 2, and
        % then forwarded to STORAGE 3(AC0),4(AC1),5(AC2),6(AC3) based on
        % Priority. When entered, set the numFrame_ACx counter; The 1st
        % frame in the AC queue starts 'Listen process' immediately.
        
        % 2. Frame to be transmitted will be 'FORWARD' to STORAGE 7 (HCF
        % storage); When entered, set internal contention to busy status
        % (intContention=1); Start to do external contention check
        % (extContentionCheck);
        function [entity,events]=frameEntry(obj,storage,entity,~)
            coder.extrinsic('num2str');    
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('mac');
            events=obj.initEventArray;                
                switch storage
                    case 3          %AC0                               
                        obj.numFrame_AC0=obj.numFrame_AC0+1;                        
                        disp(['numFrame_AC0 ' num2str(obj.numFrame_AC0)]);
                        if obj.numFrame_AC0==1                             
                            events=obj.hcfListen(entity,'AC0Listen');
%                             obj.isFirstAC0=0;
                        end
                    case 4          %AC1  
%                         disp(['numFrame_AC1' num2str(obj.numFrame_AC1)]);
                        obj.numFrame_AC1=obj.numFrame_AC1+1;
                        if obj.numFrame_AC1==1
                            events=obj.hcfListen(entity, 'AC1Listen');
%                             obj.isFirstAC1=0;
                        end
                    case 5          %AC2                        
                        obj.numFrame_AC2=obj.numFrame_AC2+1;                        
                        if obj.numFrame_AC2==1
                            events=obj.hcfListen(entity,'AC2Listen');
%                             obj.isFirstAC2=obj.isFirstAC2-1;
                        else
                            events=obj.eventIterate(5,'clearOldFramesforNewBSMs',1);
                        end
                    case 6          %AC3
%                         disp(['numFrame_AC3' num2str(obj.numFrame_AC3)]);
                        obj.numFrame_AC3=obj.numFrame_AC3+1;
                        if obj.numFrame_AC3==1
                            events=obj.hcfListen(entity,'AC3Listen');
%                             obj.isFirstAC3=0;
                        end   
                    case 7           %HCF Tx buffer
%                         disp('frame enters storage 7,start extCon check');                        
                        [entity,events]=obj.extContentionCheck(entity);   
                end          
        end
        
        
        function [entity,events]=payloadGenerate(obj,storage,entity,tag)
            coder.extrinsic('evalin');
            coder.extrinsic('app_msg2wsmp');
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('mac');
            assert(storage==10);
            events=obj.initEventArray;
            tag=tag(tag~=0);
            switch tag               
                case 'RxPayload'
                    entity.data.wsmp=obj.rxPayloadBuffer;                    
                    events=obj.eventForward('output',1,0);
                case 'mgmGenACKed'                    
                    disp('Generate management frames for ACK.');
                    msgType=111;
                    entity.data.wsmp=app_msg2wsmp(msgType,entity.data.wsmp,1); 
                    entity.data.wsmp=app_msg2wsmp(abs('A'),entity.data.wsmp,2);
                    events=obj.eventForward('output',1,0);
                case 'mgmGenUnACKed'                    
                    disp('Generate management frames for UnACK.');
                    msgType=111;
                    entity.data.wsmp=app_msg2wsmp(msgType,entity.data.wsmp,1); 
                    entity.data.wsmp=app_msg2wsmp(abs('U'),entity.data.wsmp,2);
                    events=obj.eventForward('output',1,0);
            end
            
        end                
            
        function [entity,events]=waveformEntry(obj,~,entity,~)    
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('phy');
            coder.extrinsic('num2str');
            events=obj.initEventArray;
            distance=sqrt((entity.data.pos(1)-obj.payloadPosBuffer(1))^2+(entity.data.pos(2)-obj.payloadPosBuffer(2))^2);
            airPropDelay=distance/(3*10^8);
                                                                
            if airPropDelay~=0
                events=obj.eventTimer('rcvWaveform',airPropDelay);                                                
%                 disp([num2str(obj.getCurrentTime()*1000000) '--waveformEntry--' num2str(airPropDelay*1000000)]);
            end
        end        
        
        function [entity,events]=waveformTimer(obj,storage,entity,tag)
            coder.extrinsic('num2str');                
            coder.extrinsic('str2double');            
%             coder.extrinsic('phy_waveform2psdu_ACK');            
            coder.extrinsic('phy_waveform2psdu_data');
            coder.extrinsic('phy_waveform2psdu_ack');
            coder.extrinsic('fcn_carGlobalDB');
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('phy');
            events=obj.initEventArray();
            
            tag=tag(tag~=0);
            
            if strcmp(tag,'rcvWaveform')                
%                 disp([num2str(obj.getCurrentTime()*1000000) 'waveformTimer']);
                obj.numRx=obj.numRx+1;        

                status=1;
                outframe=zeros(1,800);
                outmsg='1234567';
                typeField=1;
                subtype=1;


                if entity.data.Address2~=obj.txAddr
                    distance=sqrt((entity.data.pos(1)-obj.payloadPosBuffer(1))^2+(entity.data.pos(2)-obj.payloadPosBuffer(2))^2);
                    SNR =phy_pathlost(distance);            
                else
                    SNR=40;
                end



                if sum(entity.data.ACKBody)==0  % Receive Data  
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  receives ' num2str(obj.numRx) ' data.']);                      
                    end
                    [ status, outframe, outmsg, typeField, subtype ] = phy_waveform2psdu_data(entity.data.Body,SNR,entity.data.Length );       
                else
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  receives ' num2str(obj.numRx) ' ACK.']);  
                    end
                    [ status, ~, outmsg, typeField, subtype ] = phy_waveform2psdu_ack(entity.data.ACKBody,SNR,entity.data.Length );
                end            

                if status==1 %Received correctly  
                    rcvAddress=zeros(1,2);
                    if entity.data.Address1>1000000
                        tempAdd='1000000';
                        tempAdd=num2str(entity.data.Address1);                                        
                        rcvAddress(1)=str2double(tempAdd(2:4));
                        rcvAddress(2)=str2double(tempAdd(5:7));                     
                    elseif entity.data.Address1>0                    
                        rcvAddress(1)=entity.data.Address1;
                    end


                    obj.rxCRCerr=0;
    %                 if (entity.data.ToDS==0 && entity.data.FromDS==0 && entity.data.Address1==obj.txAddr)... % V2V unicast packet
                    if (entity.data.ToDS==0 && entity.data.FromDS==0 && ismember(obj.txAddr,rcvAddress))... % V2V unicast packet
                    || (entity.data.ToDS==0 && entity.data.FromDS==0 && entity.data.Address1==0 && entity.data.Address2~=obj.txAddr)...          % V2V broadcast packet
                    || (entity.data.ToDS==0 && entity.data.FromDS==1 && entity.data.Address1==0 && entity.data.Address2==obj.infraAddress && entity.data.Address3~=obj.txAddr)... %V2I broadcast packet
                    || (entity.data.ToDS==0 && entity.data.FromDS==1 && entity.data.Address1==obj.txAddr && entity.data.Address2==obj.infraAddress && entity.data.Address3~=obj.txAddr)    %V2I unicast packet
    %                     switch outframe.typeField                           
                       switch typeField
                            case 1              % Rcv ACK: type -> 1 subtype -> 13
                                if subtype==13    %receive ACK
                                    if entity.data.Address1==obj.txAddr
    %                                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node'  num2str(obj.txAddr) ' ACK SN: ' num2str(entity.data.SN) ' Unacked Packet SN: ' num2str(obj.waitForACK)]);                                                                                                                
                                        if ismember(entity.data.SN,obj.waitForACK)  % Make sure the ACK is to the right data%   
                                            if obj.txtEnable==1                                                
                                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  frame ' num2str(entity.data.SN) ' is acked successfully!']);                            %                                           
                                            end
                                            
                                            obj.RxACKSN=entity.data.SN;   

                                            events=[obj.eventIterate(7,'ackOK',1)...                                                          
                                            obj.eventDestroy()];

                                            % -----------Performance lane changing special                                       
                                            if strcmp(obj.brakeMode,'PerLaneChange') && entity.data.Address2==obj.PLCA                                                
                                                events=[events obj.eventGenerate(10,'mgmGenACKed',0,10)];
                                            end
                                            %-----------------------------------------------------------------

                                            for i=1:length(obj.waitForACK)
                                                if obj.waitForACK(i)==entity.data.SN    
                                                    obj.waitForACK(i)=0;        
                                                    tempArray=obj.waitForACK(obj.waitForACK~=0);        
                                                    tempIndex=length(tempArray);        
                                                    obj.waitForACK(1:tempIndex)=tempArray;        
                                                end 
                                            end
                                        else  % ACK is not to the right data
                                            if obj.txtEnable==1    
                                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node'  num2str(obj.txAddr) 'This ACK is invalid,i.e., sequence number does not match, discard!']); %        
                                            end    
                                            events=obj.eventDestroy();    
                                        end                                                                                                                                                                            
                                    else
                                        if obj.txtEnable==1
                                            disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node'  num2str(obj.txAddr) 'This ACK is not for me, discard!']);
                                        end
                                        events=obj.eventDestroy();
                                    end        
                                else
                                    if obj.txtEnable==1
                                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node'  num2str(obj.txAddr) 'This is not an ACK frame']);
                                    end
                                    events=obj.eventDestroy();
                                end

                            case 2              % Rcv data: type -> 2   

                                if entity.data.Address1==0 || (entity.data.Address1>=1000000&&ismember(obj.txAddr,rcvAddress)) % Broadcast or multicast  packet, do not send ACK back
                                    fcn_carGlobalDB('latency',entity.data.ACTag,obj.getCurrentTime()-entity.data.Timestamp);

                                    if obj.txtEnable==1
                                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' received from broadcast correctly!  No ACK needed.']);
                                    end
                                    obj.RxDataSN=entity.data.SN;

                                    obj.rxPayloadBuffer=outframe;
                                    events=[obj.eventGenerate(10,'RxPayload',0,20)...   % send payload to upper layer
                                            obj.eventDestroy()];                            
                                elseif obj.txAddr == entity.data.Address1 % This is a unicast packet, need to send ACK back                                                            
                                    fcn_carGlobalDB('latency',entity.data.ACTag,obj.getCurrentTime()-entity.data.Timestamp);
                                    if entity.data.FromDS==1
                                        if obj.txtEnable==1
                                            disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': data ' num2str(entity.data.SN) ' received from node' num2str(entity.data.Address3) 'via AP ' num2str(entity.data.Address2)  ' correctly!  Prepare for ACK......']);
                                        end
                                    elseif entity.data.FromDS==0
                                        if obj.txtEnable==1
                                            disp(['TTTTTTTTTT= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': data ' num2str(entity.data.SN) ' received from node' num2str(entity.data.Address2) ' correctly!  Prepare for ACK......']);
                                        end
                                    end
                                    obj.RxDataSN=entity.data.SN;                                
                                    if entity.data.ToDS==0 && entity.data.FromDS==0
                                        obj.srcAddress=entity.data.Address2;
                                    elseif entity.data.ToDS==0 && entity.data.FromDS==1
                                        obj.srcAddress=entity.data.Address3;
                                    end                                                                
                                    obj.rxPayloadBuffer=outframe;
                                    events=[obj.eventGenerate(8,'sendACK',obj.SIFS,100)...     % generate ACK
                                            obj.eventGenerate(10,'RxPayload',0,20)...   % send payload to upper layer
                                            obj.eventDestroy()];

                                else
                                    if obj.txtEnable==1
                                        disp('This msg is not for me, discard!');
                                    end
                                    events=obj.eventDestroy();
                                end                        
                        end     
                    else % Invalid ToDS/FromDS/Address
    %                     disp(['entity.data.ToDS ' num2str(entity.data.ToDS) ' entity.data.FromDS ' num2str(entity.data.FromDS) ' entity.data.Address1 ' num2str(entity.data.Address1)]);
                        if obj.txtEnable==1
                            disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': receive correct packets but not for me.' ]);
                        end
                        events=obj.eventDestroy();
                    end
                elseif status==0 %Corrupted
                    obj.rxCRCerr=1;
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': ' outmsg '--> destroyed!']);
                    end
                    if (entity.data.ToDS==0 && entity.data.FromDS==0 && entity.data.Address1==obj.txAddr) || (entity.data.ToDS==0 && entity.data.FromDS==1 && entity.data.Address2==obj.infraAddress) || (entity.data.ToDS==0 && entity.data.FromDS==0 && entity.data.Address1==0)
                        if sum(entity.data.ACKBody)==0  % Receive Data  

                            fcn_carGlobalDB('CRCerror',entity.data.ACTag);
                        end
                    end
                    events=obj.eventDestroy();                
                end   
            end
        end
        
        function [entity,events,next]=frameIterate(obj,~,entity,tag,cur)
            coder.extrinsic('num2str');
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('mac');
            next=false;
            events=obj.initEventArray;
            tag=tag(tag~=0);
            switch tag
                case 'ackOK'
                    if entity.data.SN==obj.RxACKSN
                        switch entity.data.ACTag
                            case 0
%                                 disp('Frame from AC0 is destroyed');
                                if obj.numFrame_AC0>=1
                                    events=obj.eventIterate(3,'nextAC0',10);
                                else
%                                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': no more frames in AC0...']);
%                                     obj.isFirstAC0=1;
                                end
                            case 1
%                                 disp('Frame from AC1 is destroyed')
                                if obj.numFrame_AC1>=1
                                    events=obj.eventIterate(4,'nextAC1',10);
                                else
%                                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': no more frames in AC1...']);
%                                     obj.isFirstAC1=1;
                                end
                            case 2
%                                 disp('frame from AC2 is destroyed');
                                if obj.numFrame_AC2>=1
                                    events=obj.eventIterate(5,'nextAC2',10);
                                else
%                                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': no more frames in AC2...']);
%                                     obj.isFirstAC2=1;
                                end
                                
                            case 3
%                                 disp(['frame from AC3 is destroyed' num2str(obj.numFrame_AC3)]);
                                if obj.numFrame_AC3>=1
                                    events=obj.eventIterate(6,'nextAC3',10);
                                else
%                                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': no more frames in AC3...']);
%                                     obj.isFirstAC3=1;
                                end
                        end
                        events=[events obj.eventDestroy()];
                        next=false;
                    else
%                         events=obj.initEventArray;
                        next=true;
                    end
                case 'nextAC0'
                    if obj.txtEnable==1
                        disp('Iterate AC0');   
                    end
                    if cur.position==1
                        events=obj.hcfListen(entity,'AC0Listen');
                        next=false;
                    end
                case 'nextAC1'
                    if obj.txtEnable==1
                        disp('Iterate AC1');
                    end
                    if cur.position==1
                        events=obj.hcfListen(entity, 'AC1Listen');
                        next=false;
                    end
                case 'nextAC2'
                    if obj.txtEnable==1
                        disp('Iterate AC2');
                    end
                    if cur.position==1
                        events=obj.hcfListen(entity, 'AC2Listen');
                        next=false;
                    end
                case 'nextAC3'
                    if obj.txtEnable==1
                        disp('Iterate AC3');
                    end
                    if cur.position==1
                        events=obj.hcfListen(entity, 'AC3Listen');
                        next=false;
                    end
                case 'clearOldFramesforNewBSMs'
                    if cur.position<cur.size
                        events=obj.eventDestroy();
                        obj.numFrame_AC2=obj.numFrame_AC2-1;
                        next=true;
                    else
                        disp('old frames in AC2 are cleared');
                        events=obj.hcfListen(entity,'AC2Listen');
                    end
            end
        end
        

        function events=waveformDestroy(obj,storage,~)
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('phy');
            assert(storage==9);            
            obj.numRx=obj.numRx-1;
            events=obj.initEventArray;        
        end
        
        % waveform generated in Storage 8, ready to send.
        function [entity,events]=waveformGenerate(obj,~,entity,tag) 
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('phy');
            coder.extrinsic('phy_psdu2waveform_ack_mex');
            coder.extrinsic('phy_psdu2waveform_data_mex');
            tag=tag(tag~=0);
            entity.data.pos=obj.payloadPosBuffer;
            switch tag                                    
                case 'sendACK'  % Send ACK
                    entity.sys.priority=1;
                    entity.data.Control=13;
                    entity.data.SN=obj.RxDataSN;
%                     [entity.data.ACKBody,entity.data.Length]=phy_psdu2waveform(1,obj.srcAddress);                                                           
                    [entity.data.ACKBody,entity.data.Length]=phy_psdu2waveform_ack_mex(obj.srcAddress);
                    if strcmp(obj.V2Xmode,'V2V')
                        entity.data.ToDS=0;
                        entity.data.FromDS=0;
                        entity.data.Address1=obj.srcAddress;
                        entity.data.Address2=obj.txAddr;
                    elseif strcmp(obj.V2Xmode,'V2I')
                        entity.data.ToDS=1;
                        entity.data.FromDS=0;
                        entity.data.Address1=obj.infraAddress;
                        entity.data.Address2=obj.txAddr;
                        entity.data.Address3=obj.srcAddress;                        
                    else
                        if obj.txtEnable==1
                            disp('Error: wrong V2x mode selected.');
                        end
                        
                    end
                    % turn off ack sending temporarily
                    events=obj.eventForward('output',2,0);   
%                     events=obj.initEventArray;
                    
                otherwise %Send data waveform
                    entity.data.Control=8;
                    entity.data.SN=obj.frameSNBuffer;       
                    entity.data.Timestamp=obj.timestampBuffer;
                    %Convert psdu to waveform
%                     [waveform,entity.data.Length]=phy_psdu2waveform(0,obj.txAddr,obj.dstAddress,obj.frameBodyBuffer);          
                    [waveform,entity.data.Length]=phy_psdu2waveform_data_mex(obj.txAddr,obj.dstAddress,obj.frameBodyBuffer); 
                    entity.data.Body=waveform;                        
                    switch tag
                        case 'sendFrame_AC0'
                            entity.data.ACTag=0;
                            entity.sys.priority=40;
                        case 'sendFrame_AC1'
                            entity.data.ACTag=1;
                            entity.sys.priority=30;
                        case 'sendFrame_AC2'
                            entity.data.ACTag=2;
                            entity.sys.priority=20;
                        case 'sendFrame_AC3'
                            entity.data.ACTag=3;
                            entity.sys.priority=10;
                    end    

                    if strcmp(obj.V2Xmode,'V2V')
                        entity.data.Address1=obj.dstAddress; % Destination address
                        entity.data.Address2=obj.txAddr;     % Sender address                                   
                        entity.data.ToDS=0;
                        entity.data.FromDS=0;
                    elseif strcmp(obj.V2Xmode,'V2I')
                        entity.data.ToDS=1;
                        entity.data.FromDS=0;
                        entity.data.Address1=obj.infraAddress; % AP address
                        entity.data.Address2=obj.txAddr;       % Sender address
                        entity.data.Address3=obj.dstAddress;   % Destination address
                    else
                        if obj.txtEnable==1
                            disp('Warning: V2x mode error! (0 or 1)')
                        end
                        
                    end
                    
                    events=obj.eventForward('output',2,0);
                    
            end
        end                                    
       
        function events=waveformExit(obj,storage,entity,~)
            coder.extrinsic('num2str');
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('phy');
            events=obj.initEventArray;
            if storage ==8
                if entity.data.Control==8
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  waveform' num2str(entity.data.SN) ' sent.'])
                    end
                elseif entity.data.Control==13
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  ACK' num2str(entity.data.SN) ' is sending...'])
                    end
                end                
            end
        end
        
        function [entity,events]=frameTimer(obj,storage,entity,tag)   
            coder.extrinsic('fcn_eventsCount');            
            fcn_eventsCount('mac');
            events=obj.initEventArray;
            coder.extrinsic('phy_ChannelSensing');
            coder.extrinsic('num2str');
            hcfCS=1;
            hcfCS=phy_ChannelSensing(1,0,0); % Channel sensing
            tag=tag(tag~=0);
            switch tag                
                case {'AC0Listen','AC1Listen','AC2Listen','AC3Listen'}                       
                    events=obj.hcfListen(entity,tag);               
                case 'AC0AIFS'                    
                    if hcfCS==0  %Channel free
                        
                        if obj.backoffPause==0   % new backoff 
    %                       disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' starts backoff!']);
                            events=obj.hcfBfStart(entity,'AC0backoff');% backoff
                        else % resume backoff 
                           if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' resumes backoff!']);
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC0 Backoff left:' num2str(obj.backoff_AC0) '----------']);                    
                           end
                           events=obj.hcfBfCont('AC0backoff',entity);
%                             events=obj.eventTimer('AC0backoff',0);
                           obj.backoffPause=0;
                        end    
                        
                    else
                        events=obj.hcfListen(entity,'AC0Listen');
                    end
                case 'AC1AIFS'
                    if hcfCS==0   %Channel free
                         if obj.backoffPause==0                              
                            %backoff start
    %                       disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' starts backoff!']);
                            events=obj.hcfBfStart(entity,'AC1backoff');% backoff
                         else
                           %backoff resume
                           if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' resumes backoff!']);
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC1 Backoff left:' num2str(obj.backoff_AC1) '----------']);                    
                           end
                           events=obj.hcfBfCont('AC1backoff',entity);      
%                             events=obj.eventTimer('AC0backoff',0);
                           obj.backoffPause=0;
                         end                    
                    else
                        events=obj.hcfListen(entity,'AC1Listen');
                    end
                case 'AC2AIFS'
                    if hcfCS==0   %Channel free
                         if obj.backoffPause==0              %backoff start
    %                       disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' starts backoff!']);
                            events=obj.hcfBfStart(entity,'AC2backoff');% backoff
                         else %backoff resume
                             if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' resumes backoff!']);
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC2 Backoff left:' num2str(obj.backoff_AC2) '----------']);                    
                             end
                           events=obj.hcfBfCont('AC2backoff',entity);    
%                             events=obj.eventTimer('AC0backoff',0);
                           obj.backoffPause=0;
                         end                                                      
                    else
                        events=obj.hcfListen(entity,'AC2Listen');
                    end
                case 'AC3AIFS'   
                    if hcfCS==0   %Channel free
                         if obj.backoffPause==0                              
                            %backoff start
    %                       disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' starts backoff!']);
                            events=obj.hcfBfStart(entity,'AC3backoff');% backoff
                         else
                           %backoff resume
                           if obj.txtEnable==1
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': frame ' num2str(entity.data.SN) ' resumes backoff!']);
                                disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC3 Backoff left:' num2str(obj.backoff_AC3) '----------']);                    
                           end
                           events=obj.hcfBfCont('AC3backoff',entity);     
%                             events=obj.eventTimer('AC0backoff',0);
                           obj.backoffPause=0;
                         end
                    else
                        events=obj.hcfListen(entity,'AC3Listen');
                    end
                %Backoff timer
                case 'AC0backoff'
%                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': Frame' num2str(entity.data.SN) ' backoff .......']);
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC0 Backoff left:' num2str(obj.backoff_AC0) '----------']);                    
                    end
                        if obj.backoff_AC0==0 % backoff counter reach to zero, transmit immediatelly
                            if hcfCS==0
                                if entity.data.Retry==0
                                        events=obj.intContentionCheck(entity);
                                else                      
                                        [entity,events]=obj.extContentionCheck(entity);  
                                end    
                            else
                                obj.backoffPause=1;
                                events=obj.hcfListen(entity,'AC0Listen');
                            end
                            
                        else
                            if hcfCS==0  % Channel free, keep backoff 
                                events=obj.hcfBfCont(tag,entity);                        
                            else % Channel busy, pause backoff and listen
                                obj.backoffPause=1;
                                events=obj.hcfListen(entity,'AC0Listen');
                            end
                        end   
                case 'AC1backoff'
%                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ':  Frame' num2str(entity.data.SN) ' backoff .......']);
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC1 Backoff left:' num2str(obj.backoff_AC1) '----------']);                    
                    end
                        if obj.backoff_AC1==0 % backoff counter reach to zero, transmit immediatelly
                            if hcfCS==0
                                if entity.data.Retry==0
                                        events=obj.intContentionCheck(entity);
                                else                      
                                        [entity,events]=obj.extContentionCheck(entity);  
                                end   
                            else
                                obj.backoffPause=1;
                                events=obj.hcfListen(entity,'AC1Listen');
                            end
                            
                        else
                            if hcfCS==0  % Channel free, keep backoff 
                                events=obj.hcfBfCont(tag,entity);                        
                            else % Channel busy, pause backoff and listen
                                obj.backoffPause=1;
                                events=obj.hcfListen(entity,'AC1Listen');
                            end
                        end   
                case 'AC2backoff'
%                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': Frame' num2str(entity.data.SN) ' backoff .......']);       
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC2 Backoff left:' num2str(obj.backoff_AC2) '----------']);                    
                    end
                        if obj.backoff_AC2==0 % backoff counter reach to zero, transmit immediatelly
                            if hcfCS==0
                                if entity.data.Retry==0
                                        events=obj.intContentionCheck(entity);
                                else                      
                                        [entity,events]=obj.extContentionCheck(entity);  
                                end   
                            else % Channel busy, pause backoff and listen
                                obj.backoffPause=1;
                                events=obj.hcfListen(entity,'AC2Listen');
                            end
                            
                        else
                            if hcfCS==0  % Channel free, keep backoff 
                                events=obj.hcfBfCont(tag,entity);                        
                            else % Channel busy, pause backoff and listen
                                obj.backoffPause=1;
                                events=obj.hcfListen(entity,'AC2Listen');
                            end
                        end   
                case 'AC3backoff'
%                     disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': Frame' num2str(entity.data.SN) ' backoff .......']);
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) '-------AC3 Backoff left:' num2str(obj.backoff_AC3) '----------']);                    
                    end
                        if obj.backoff_AC3==0 % backoff counter reach to zero, transmit immediatelly
                            if hcfCS==0
                                if entity.data.Retry==0
                                        events=obj.intContentionCheck(entity);
                                else                      
                                        [entity,events]=obj.extContentionCheck(entity);  
                                end
                            else % Channel busy, pause backoff and listen
                                obj.backoffPause=1;
                                events=obj.hcfListen(entity,'AC3Listen');
                            end
                        else
                            if hcfCS==0  % Channel free, keep backoff 
                                events=obj.hcfBfCont(tag,entity);                        
                            else % Channel busy, pause backoff and listen
                                obj.backoffPause=1;
                                events=obj.hcfListen(entity,'AC3Listen');
                            end
                        end                       
                %Data transmission timer    
                case 'dataTx'                                                                      
                    events=obj.eventTimer('ackTimeout',obj.ackTimeout);  
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ' acktimeout set: ' num2str(obj.ackTimeout*1000) 'ms']);                   
                    end
                    obj.intContention=0;
                case 'ackTimeout'
                    assert(storage==7);
                    if obj.txtEnable==1
                        disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': ACK' num2str(entity.data.SN) '  not received, start retransmission<<<<<<<<<<']);
                    end
                    disp(['(ackTimeout) entity.data.Address1 ' num2str(entity.data.Address1) 'entity.data.Address2 ' num2str(entity.data.Address2) 'entity.data.Address3 ' num2str(entity.data.Address3)]);
                    entity.data.Retry=1;
                    disp(['T= ' num2str(obj.getCurrentTime()*1000) 'ms' ',  node' num2str(obj.txAddr) ': Retry times  (ack Timeout)' num2str(entity.data.Retry)]);                
                    events=obj.hcfReTx(entity);
                case 'broadcast'
                    events=obj.eventDestroy();                   
                    obj.intContention=0;
            end            
        end
    end
    
    
end